<?php

/**
 * 海关对接service
 */
namespace data\service\cdkjt;


use data\extend\cdkjt\Cdkjt;
use data\model\UserModel;
use data\model\VslCdkjtLogModel;

use data\model\VslGoodsSkuModel;
use data\model\VslOrderCustom;
use data\model\VslOrderCustomPaymentModel;
use data\model\VslOrderCustomSign;
use data\model\VslOrderGoodsModel;

use data\model\VslOrderModel;
use data\service\Config;
use data\service\Pay\WeiXinPay;
use think\Exception;

class CdkjtService
{


    public static $queue_payments = 'hg_payment';              //海关支付清关队列

    public static $queue_customs = 'hg_custom';              //海关查询订单队列名称

    public static $queue_signs = 'hg_getsign';                      //签名获取队列名称

    public static $queue_orders = 'hg_custom_orders';                  //签名成功，待上传海关队列

    public static $queue_notify = 'hg_custom_notify';                  //海关回执信息队列

    private $CdkSdk;

    public function __construct()
    {
        $this->CdkSdk = new Cdkjt();
    }


    //支付后申报
    public function paymentTo($orderid,$appType = 1){     //1新增，2=变更
        $OrderModel = new VslOrderModel();
        $order = $OrderModel->getInfo(['order_id'=>$orderid]);
        $type = 'payment';
        if(!$order){
            return;
        }
        $cdn = [
            'obj_id'  =>    $orderid,
            'type'    =>    $type,
        ];
        $log = VslCdkjtLogModel::where($cdn)->find();
        if($log){
            if($appType == 1){
                return;
            }
            $guid = $log['guid'];
        }else{
            $guid = $this->CdkSdk->create_guid();
        }

        $data = [
            'guid'              =>  $guid,
            'appType'           =>  $appType,
            'appStatus'         =>  2,//申报
            'payTransactionId'  =>  $order['out_trade_no'],
            'orderNo'           =>  $order['order_no'],
            'payerIdType'       =>  1,
            'payerIdNumber'     =>  $order['id_number'],
            'payerName'         =>  $order['realname'],
            'telephone'         =>  UserModel::where(['uid'=>$order['buyer_id']])->value('user_tel'),
            'amountPaid'        =>  $order['order_money'],
            'currency'          =>  142,
            'payTime'           =>  date('YmdHis',$order['pay_time']),
            'note'              =>  ''
        ];
        $rs = $this->CdkSdk->payment($data);

        if($rs['PaymentReturn']){
            $saveData = [
                'status'    =>  $rs['PaymentReturn']['returnStatus'],
                'info'      =>  $rs['PaymentReturn']['returnInfo'],
                'createtime'=>  $rs['PaymentReturn']['returnTime'],
                'type'      =>  $type,
                'guid'      =>   $rs['PaymentReturn']['guid'],
                'obj_id'    =>  $orderid,
                'payTransactionId'  =>  $rs['PaymentReturn']['payTransactionId'],
                'orderno'   =>  $order['order_no'],
                'content'   =>  json_encode($rs),

            ];
            if($log){
                VslCdkjtLogModel::update($saveData,['id'=> $log['id']]);
            }else{
                $saveData['obj_id'] = $orderid;
                $saveData['guid'] = $guid;
                $saveData['type'] = $type;
                VslCdkjtLogModel::create($saveData);
            }
        }
        return $rs;
    }




    /**
     * 订单报文申报
     *
     * @param string guid 企业系统生成36位唯一序号（英文字母大写）。
     * @param int appType 企业报送类型。1-新增 2-变更
     * @param string appTime 企 业 报 送 时 间 。 格式:YYYYMMDDhhmmss。
     * @param int appStatus 业务状态:1-暂存,2-申报
     * @param string orderType 电子订单类型：I进口
     * @param string orderNo 交易平台的订单编号，同一交易平台的订单编号应唯一。订单编号长度不能超过60位
     * @param string ebpCode 电商平台的海关注册登记编号；电商平台未在海关注册登记，由电商企业发送订单的，以中国电子口岸发布的电商平台标识编号为准
     * @param string ebpName 电商平台的海关注册登记名称；电商平台未在海关注册登记，由电商企业发送订单的，以中国电子口岸发布的电商平台名称为准
     * @param string ebcCode 电商企业的海关注册登记编号
     * @param string ebcName 电商企业的海关注册登记名称
     * @param float goodsValue 商品实际成交价，含非现金抵扣金额
     * @param float freight 不包含在商品价格中的运杂费，无则填写"0"
     * @param float discount 使用积分、虚拟货币、代金券等非现金支付金额，无则填写"0"
     * @param float taxTotal 企业预先代扣的税款金额，无则填写“0”
     * @param float acturalPaid 商品价格+运杂费+代扣税款非现金抵扣金额，与支付凭证的支付金额一致
     * @param string currency 限定为人民币，填写“142”
     * @param string buyerRegNo 订购人的交易平台注册号
     * @param string buyerName 订购人的真实姓名
     * @param string buyerTelephone 海关监管对象的电话，要求实际联系电话
     * @param string buyerIdType 1-身份证,2-其它。限定为身份证，填写“1”
     * @param string buyerIdNumber 订购人的身份证件号码
     * @param string payCode 支付企业的海关注册登记编号
     * @param string payName 支付企业在海关注册登记的企业名称
     * @param string payTransactionId 支付企业唯一的支付流水号
     * @param string batchNumbers 商品批次号
     * @param string consignee 收货人姓名，必须与电子运单的收货人姓名一致
     * @param string consigneeTelephone 收货人联系电话，必须与电子运单的收货人电话一致
     * @param string consigneeAddress 收货地址，必须与电子运单的收货地址一致
     * @param string consigneeDistrict 收货地址行政区划代码,参照国家统计局公布的国家行政区划标准填制
     * @param string note 备注
     * @param string gnum 商品序号，从1开始的递增序号
     * @param string itemNo 电商企业自定义的商品货号（SKU）
     * @param string itemName 交易平台销售商品的中文名称
     * @param string gmodel 商品规格型号，满足海关归类、审价以及监管的要求为准。包括：品名、牌名、规格、型号、成份、含量、等级等
     * @param string itemDescribe 交易平台销售商品的描述信息
     * @param string barCode 国际通用的商品条形码，一般由前缀部分、制造厂商代码、商品代码和校验码组成
     * @param string unit 单位，填写海关标准的参数代码，参照《JGS-20 海关业务代码集》计量单位代码
     * @param string qty 商品实际数量
     * @param float price 商品单价。赠品单价填写为“0”
     * @param float totalPrice 商品总价，等于单价乘以数量
     * @param string currency 限定为人民币，填写“142”
     * @param string country 原产国，填写海关标准的参数代码，参照《JGS-20 海关业务代码集》-国家（地区）代码表
     * @param string note 备注，促销活动，商品单价偏离市场价格的，可以在此说明
     * @param string keyInfo 企业身份key
     *
     */
    public function order($orderid,$appType=1)
    {
        $OrderModel = new VslOrderModel();
        $order = $OrderModel->getInfo(['order_id'=>$orderid]);
        $ordertype = [
            1   =>  '普通订单',
            5   =>  '拼团订单',
            6   =>  '秒杀订单',
            7   =>  '预售订单',
            8   =>  '砍价订单',
            9   =>  '奖品订单',
            11  =>  '微店订单',
            12  =>  '门店订单'
        ];

        $data = [
            'appType'           =>  $appType,
            'appStatus'         =>  2,//申报
            'orderType'         =>  'I',
            'payTransactionId'  =>  $order['out_trade_no'],
            'orderNo'           =>  $order['order_no'],
            'buyerIdType'       =>  1,
            'buyerIdNumber'     =>  $order['id_number'],
            'buyerName'         =>  $order['realname'],
            'buyerTelephone'    =>  UserModel::where(['uid'=>$order['buyer_id']])->value('user_tel'),
            'currency'          =>  "142",
            'goodsValue'        =>  $order['order_money']+$order['deduction_money'],
            'freight'           =>  $order['shipping_money'],
            'discount'          =>  $order['deduction_money'],
            'taxTotal'          =>  $order['tax_money'],
            'acturalPaid'       =>  $order['order_money'],
            'buyerRegNo'        =>  $order['buyer_id'],
            'consignee'         =>  $order['receiver_name'],
            'consigneeTelephone'=>  $order['receiver_mobile'],
            'consigneeAddress'  =>  $order['receiver_address'],
            'consigneeDistrict' =>  '',
            'note'              =>  $ordertype[$order['order_type']]??'普通订单',
        ];
        $orderGoodsModel = new VslOrderGoodsModel();
        $orderGoodsMap = [
            'order_id'      =>  $orderid,
            'refund_status' =>  0,
        ];
        $orderGoods = $orderGoodsModel->where($orderGoodsMap)->select();
        $orderList = [];
        $gnum = 1;
        foreach ($orderGoods as $k=>$item){

            $goodsSku = VslGoodsSkuModel::where(['sku_id'=>$item['sku_id']])->field('code,QRcode')->find();

            $gmodel = !empty($item['sku_attr'])?$item['sku_attr']:$item['sku_name'];
            if(empty($gmodel)){
                $gmodel = '默认规格';
            }


            $orderList[$k] = [
                'gnum'          =>  $gnum,
                'itemName'      =>  $item['goods_name'],
                'unit'          =>  '124',
                'qty'           =>  $item['num'],
                'price'         =>  $item['price'],
                'totalPrice'    =>  $item['goods_money'],
                'currency'      =>  142,
                'country'       =>  116,
                'gmodel'        =>  $gmodel,
                'itemNo'        =>  $goodsSku['code'],
                'barCode'       =>  $goodsSku['QRcode'],
                'itemDescribe'  =>  $item['sku_name'],
                'note'          =>  ''
            ];
            $gnum++;
        }
        $data['orderList'] = $orderList;
        $rs = $this->CdkSdk->order($data);
        if($rs && $rs['OrderReturn']){
            $type = 'order';
            $cdn = [
                'orderno'   =>  $order['order_no'],
                'type'      =>  $type,
            ];
            $log = VslCdkjtLogModel::where($cdn)->find();
            $saveData = [
                'status'    =>  $rs['OrderReturn']['returnStatus'],
                'info'      =>  $rs['OrderReturn']['returnInfo'],
                'createtime'=>  $rs['OrderReturn']['returnTime'],
                'type'      =>  $type,
                'guid'      =>  $rs['OrderReturn']['guid'],
                'obj_id'    =>  $orderid,
                'payTransactionId'  =>  $order['out_trade_no'],
                'orderno'   =>  $order['order_no'],
                'content'   =>  json_encode($rs),
            ];
            if($log){
                VslCdkjtLogModel::update($saveData,['id'=> $log['id']]);
            }else{
                VslCdkjtLogModel::create($saveData);
            }
        }
        return $rs;
    }


    /**
     * 清单
     * @return mixed|string
     */
    public function qingdan(){
        $data['appType'] = 1;
        $data['appStatus'] = 2;
        $rs = $this->CdkSdk->qingdan($data);
        return $rs;
    }


    //物流申报
    public function wuliu(){
        $data['appType'] = 1;
        $data['appStatus'] = 2;
        $rs = $this->CdkSdk->wuliu($data);
        return $rs;
    }


    //微信支付报关
    public function wxpayment($orderNo,$type=1)
    {
        $OrderInfo = VslOrderModel::where(['order_no'=>$orderNo])->find();
        if(!$OrderInfo || empty($OrderInfo->transaction_id)){
            return;
        }
        $action_type = ($type ==1)?'ADD':'MODIFY';
        $xml = htmlspecialchars_decode($OrderInfo->pay_request);
        //$xml = simplexml_load_string($xml);
        $xmlData = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $WxPay = new WeiXinPay($OrderInfo->website_id,1);
        $key = $WxPay->getMpPayMchkey();
        $data['appid']          = $xmlData['appid'];
        $data['customs']        = 'GUANGZHOU_ZS';
        $data['mch_customs_no'] = \think\Config::get('cdkjt.ebpCode');
        $data['mch_id']         = $xmlData['mch_id'];
        $data['out_trade_no']   = $OrderInfo->out_trade_no;
        $data['transaction_id'] = $OrderInfo->transaction_id;
        //$data['fee_type'] = 'CNY';
        $data['action_type']    = $action_type;  //ADD,MODIFY
        //签名步骤二：在string后加入KEY
        $data['sign'] = $this->makeSignature($data,$key);
        //请求上传接口
        $cdkjt = new Cdkjt();
        $rs = $cdkjt->wxinPaymentTo($data);
        $update['updatetime'] = date('Y-m-d H:i:s');
        if($rs['return_code'] == 'SUCCESS' && $rs['result_code'] =='SUCCESS')
        {
            $update['status'] = 2;
            $update['verify_department_trade_id'] = $rs['verify_department_trade_id'];
            $update['remark'] = json_encode($rs);
        }else{
            $update['status'] = -1;
            $update['remark'] = $rs['err_code_des'];
        }
        VslOrderCustomPaymentModel::update($update,['order_no'=>$orderNo]);
    }


    //支付清关 队列消费
    public function CustomPaymentOrder()
    {
        //debugLog('海关-支付清关队列处理');
        while (true){
            $redis = self::connectRedis();
            $orderNo = $redis->rPop(self::$queue_payments);
            if($orderNo){
                //self::paymentTo($orderid,1);   //Todo...
                self::wxpayment($orderNo);
            }else{
                break;
            }
        }
    }



    //179签名申报
    public function getSign($data){
        $rs = $this->CdkSdk->getsign($data);
        if(!isset($rs['SignReturn'])){
            return $rs;
        }
        $copNo      = $rs['SignReturn']['copNo'];
        $signResult = $rs['SignReturn']['signResult'];
        $status     = $rs['SignReturn']['returnStatus'];
        $info       = $rs['SignReturn']['returnInfo'];
        $One        = VslOrderCustomSign::where(['copNo'=>$copNo])->find();
        if(!$One){
            return $rs;
        }
        $date = date('Y-m-d H:i:s');
        $One->status = $status;
        $One->content = $info;
        $One->updatetime = $date;
        $One->save();
        if($status == 5){       //预处理成功，更新179表的sign字段
            VslOrderCustom::update(['sign'=>$signResult,'updatetime'=>$date],['sessionID'=>$One->sessionID]);
        }
        return $rs;
    }


    /*
    * 连接redis
    * **/
    public static function connectRedis(){
        $config = new Config();
        $redis_config = $config->getRedisConfig(0);
        $host = '';
        $pwd = '';
        if($redis_config){
            $host = $redis_config['host'];
            $pwd = $redis_config['pass'];
        }
        $port = $redis_config['port']??6379;
        try {
            $redis = new \Redis();
            if($host && $pwd){
                $redis->connect($host, $port);
                $redis->auth($pwd);
            }else{
                $redis = new \Redis();
                $redis->connect('127.0.0.1', $port);
            }
            return $redis;
        }catch (Exception $e){
            return false;
        }
    }


    function makeSignature($args,$key)
    {
        ksort($args);
        $stringA = '';
        foreach($args as $k => $v) {
            $stringA .= $k . '=' . $v . '&';
        }
        $stringSignTemp =  $stringA.'key='.$key;
        $signature  = strtoupper(md5($stringSignTemp));

        return $signature;

    }


}